package com.jackrain.nea.ext.permission;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import lombok.Getter;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;

/**
 * @author lzm
 * @date 2017-11-17
 */
public class MenuCollection implements Serializable {
    private static final long serialVersionUID = -3173479788875488740L;
    @Getter
    private MenuNode rootNode = MenuNode.createRootNode();
    private HashMap<String, MenuNode> cache = new HashMap<>();  //按菜单id做的聚集索引

    private HashMap<String, Long> tmIdIndexes = new HashMap<>();  //id(菜单项下的category/table/action的主键)索引
    private Multimap<String, Long> tmNameIndexes = HashMultimap.create();   //name(菜单项下的category/table/action的name)索引

    private Multimap<Long, Long> aliasActionMap = HashMultimap.create();  //tableId-> aliasAction的集合
    private HashMap<Long, Long> allAliasActions = new HashMap<>();     //aliasActionId -> tableId

    private HashSet<Long> actions = new HashSet<>();
    private Multimap<Long, Long> actionsUnderMenuIndexes = ArrayListMultimap.create();
    private Multimap<Long, Long> actionsUnderActionIndexes = ArrayListMultimap.create();
    public MenuCollection(){
    }

    public MenuNode add(MenuNode parent,MenuNode node){
        parent.getChildren().add(node);
        cache.put(node.fetchRealId(), node);
        if(node.getNodeType() == MenuNodeType.MENU){
            tmIdIndexes.put(node.fetchRealTmId(), node.getId());
            tmNameIndexes.put(node.fetchRealTmName(), node.getId());
        }
        return node;
    }

    public boolean addActionUnderMenu(Long menuId, Long actionId){
        if(actions.add(actionId)){
            actionsUnderMenuIndexes.put(menuId, actionId);
            return true;
        }
        return false;
    }

    public void addAliasAction(Long tableId, Long aliasActionId){
        aliasActionMap.put(tableId, aliasActionId);
        allAliasActions.put(aliasActionId, tableId);
    }

    public boolean addActionUnderAction(Long parentActionId, Long actionId){
        if(actions.add(actionId)) {
            actionsUnderActionIndexes.put(parentActionId, actionId);
            return true;
        }
        return false;
    }

    public boolean containsAction(Long actionId){
        if(actionId == null || actionId <=0){
            return false;
        }
        return actions.contains(actionId);
    }

    public Collection<Long> fetchActions(Long menuId, Long actionId){
        if(actionId == null || actionId <=0){
            return actionsUnderMenuIndexes.get(menuId);
        }
        return actionsUnderActionIndexes.get(actionId);
    }

    public MenuNode fetchById(MenuNodeType nodeType, Long id){
        if(id == null || id <= 0) {
            return null;
        }
        String realId = MenuNode.fetchRealId(nodeType, id);
        return cache.get(realId);
    }

    public MenuNode fetchByTmId(MenuType type, Long tmId){
        if(tmId == null || tmId <=0) {
            return null;
        }
        Long id = tmIdIndexes.get(MenuNode.fetchRealTmId(type, tmId));
        return fetchById(MenuNodeType.MENU, id);
    }

    public Long fetchTableIdByAliasAction(Long actionId){
        return allAliasActions.get(actionId);
    }

    public Collection<Long> fetchAliasActionsByTable(Long tableId){
        return aliasActionMap.get(tableId);
    }

    public MenuNode fetchAliasActionByTable(Long tableId){
        Collection<Long> aliasActionIds = aliasActionMap.get(tableId);
        if(aliasActionIds!= null && !aliasActionIds.isEmpty()){
            for (Long aliasActionid :aliasActionIds){
                MenuNode node = fetchByTmId(MenuType.ACTION, aliasActionid);
                if(node != null){
                    return node;
                }
            }
        }
        return null;
    }

    public Collection<MenuNode> fetchByTmName(MenuType type, String tmName){
        Collection<Long> keys = tmNameIndexes.get(MenuNode.fetchRealTmName(type, tmName));
        if(keys == null || keys.size() <=0) {
            return null;
        }
        ArrayList result = new ArrayList<MenuPermissionModel>();
        for (Long key: keys){
            MenuNode model = fetchById(MenuNodeType.MENU, key);
            if(key != null){
                result.add(model);
            }
        }
        return result;
    }
}
